using System;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.Security;
using System.Xml.Serialization;
using System.DirectoryServices;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Administration;
using System.Data;
using System.Data.SqlClient;
using System.Security.Principal;
using System.Net.Mail;
using EAT.Common;

namespace EAT.UserManager
{
    [Guid("3322699d-067e-4e88-b04b-334d7b7f7b83")]
    public class UserManager : System.Web.UI.WebControls.WebParts.WebPart
    {
        [DllImport("advapi32.dll")]
        static extern bool RevertToSelf();

        cUserManager UM;
        Label DebugLabel;
        WebPartTable WPT;

        TextBox tbFirstName;
        TextBox tbLastName;
        TextBox tbPhone;
        TextBox tbCompany;

        string SelectedUserID;
        string ActionLevel;

        //
        // INDEX provides indices for the columns of the WebPartTable.
        //
        enum INDEX
        {
            ID = 0,
            FIRSTNAME,
            LASTNAME,
            COMPANY,
            PHONE,
            REQUESTER,
            ENABLED,
            EXPIRE,
            ACTION,
            Max
        }

        string[] ColumnNames;

        public UserManager()
        {
            this.ExportMode = WebPartExportMode.All;
        }

        protected override void CreateChildControls()
        {
            tbFirstName = new TextBox();
            tbFirstName.ID = "givenName";
            this.Controls.Add(tbFirstName);

            tbLastName = new TextBox();
            tbLastName.ID = "sn";
            this.Controls.Add(tbLastName);

            tbCompany = new TextBox();
            tbCompany.ID = "company";
            this.Controls.Add(tbCompany);

            tbPhone = new TextBox();
            tbPhone.ID = "telephoneNumber";
            this.Controls.Add(tbPhone);

            if (DebugLabel == null)
            {
                DebugLabel = new Label();
            }
            this.Controls.Add(
                  DebugLabel
                  );

        }

        //
        // OnLoad
        // Arguments:
        //      e - EventArgs that may contain Postback data
        // Description:
        //      Initialize internal members and respond to Postback.
        //
        protected override void OnLoad(
                                    EventArgs e
                                    )
        {
            string tag = null;
            bool b;
            string user = null;
            string action = null;
            string eventArg;
            string[] Params;
            string pwd;

            SelectedUserID = null;
            ColumnNames = new string[(int)INDEX.Max];

            DebugLabel = new Label();

            UM = new cUserManager(
                         ConfigurationManager.ConnectionStrings["ADAMConnectionString"].ConnectionString
                         );

            ColumnNames[(int)INDEX.ID] = "UserID";
            ColumnNames[(int)INDEX.FIRSTNAME] = "FirstName";
            ColumnNames[(int)INDEX.LASTNAME] = "LastName";
            ColumnNames[(int)INDEX.COMPANY] = "Company";
            ColumnNames[(int)INDEX.PHONE] = "Phone";
            ColumnNames[(int)INDEX.REQUESTER] = "Requester";
            ColumnNames[(int)INDEX.ENABLED] = "Enabled";
            ColumnNames[(int)INDEX.EXPIRE] = "Expire";
            ColumnNames[(int)INDEX.ACTION] = "Action";

            WPT = new WebPartTable("UM");

            if (IsUserManager() == false)
            {
                return;
            }

            //
            // Handle postback.
            //
            if (Page.IsPostBack)
            {
                eventArg = Page.Request["__EVENTARGUMENT"];

                if (eventArg.Length > 0)
                {
                    Params = eventArg.Split(
                                          ",".ToCharArray()
                                          );

                    //
                    // Postback must have at least 2 parameters.  The first is a tag
                    // indicating the intended target of the postback.  The second is 
                    // an action for the application to perform.
                    //
                    if (Params.Length > 1)
                    {
                        tag = Params[0];
                        action = Params[1];

                        if (WPT.GetTag() == tag)
                        {
                            switch (action)
                            {
                                case "deleteuser":
                                    {
                                        if (Params.Length == 3)
                                        {
                                            user = Params[2];
                                            SelectedUserID = user;
                                            if (UM.IsValidUsername(user))
                                            {
                                                b = DeleteUser(
                                                        user
                                                        );

                                                if (b)
                                                {
                                                    DebugLabel.Text += String.Format(Resources.UserDeletedResult, HttpUtility.HtmlEncode(user));
                                                }
                                                else
                                                {
                                                    DebugLabel.Text += String.Format(Resources.ErrorDeletingUserResult, HttpUtility.HtmlEncode(user));
                                                }
                                                DebugLabel.Text += " | ";
                                                DebugLabel.Text += @"<a href=""javascript:__doPostBack('__Page','";
                                                DebugLabel.Text += @"')"" style=""color:#333333;"">" + Resources.SubmitVerb + "</a>";
                                            }
                                        }
                                        break;
                                    }
                                case "enableuser":
                                    {
                                        if (Params.Length == 3)
                                        {
                                            user = Params[2];
                                            SelectedUserID = user;
                                            if (UM.IsValidUsername(user))
                                            {
                                                UM.ToggleUserDisabledState(
                                                    user
                                                    );

                                                DebugLabel.Text += String.Format(Resources.ChangedEnableStateResult, HttpUtility.HtmlEncode(user));

                                                DebugLabel.Text += " | ";
                                                DebugLabel.Text += @"<a href=""javascript:__doPostBack('__Page','";
                                                DebugLabel.Text += @"')"" style=""color:#333333;"">" + Resources.SubmitVerb + "</a>";
                                            }
                                        }
                                        break;
                                    }
                                case "resetpassword":
                                    {
                                        if (Params.Length == 3)
                                        {
                                            user = Params[2];
                                            SelectedUserID = user;
                                            if (UM.IsValidUsername(user))
                                            {
                                                pwd = ResetUserPassword(
                                                          user
                                                          );

                                                pwd = "<b>" + pwd + "</b>";
                                                DebugLabel.Text += String.Format(Resources.ResetPasswordResult, HttpUtility.HtmlEncode(user), pwd);

                                                DebugLabel.Text += " | ";
                                                DebugLabel.Text += @"<a href=""javascript:__doPostBack('__Page','";
                                                DebugLabel.Text += @"')"" style=""color:#333333;"">" + Resources.SubmitVerb + "</a>";
                                            }
                                        }
                                        break;
                                    }
                                case "action":
                                    {
                                        if (Params.Length == 4)
                                        {
                                            SelectedUserID = Params[2];
                                            ActionLevel = Params[3];
                                        }
                                        break;
                                    }
                                case "submitmods":
                                    {
                                        if (Params.Length == 3)
                                        {
                                            user = Params[2];
                                            SelectedUserID = user;
                                            if (UM.IsValidUsername(user))
                                            {
                                                if (UpdateUser(
                                                        user, 
                                                        HttpUtility.HtmlEncode(tbFirstName.Text), 
                                                        HttpUtility.HtmlEncode(tbLastName.Text), 
                                                        HttpUtility.HtmlEncode(tbCompany.Text), 
                                                        HttpUtility.HtmlEncode(tbPhone.Text)
                                                        ))
                                                {
                                                    DebugLabel.Text += String.Format(Resources.UpdatedUser, HttpUtility.HtmlEncode(user));

                                                    DebugLabel.Text += " | ";
                                                    DebugLabel.Text += @"<a href=""javascript:__doPostBack('__Page','";
                                                    DebugLabel.Text += @"')"" style=""color:#333333;"">" + Resources.SubmitVerb + "</a>";
                                                }
                                            }
                                        }
                                        break;
                                    }
                                case "sort":
                                    {
                                        if (Params.Length == 4)
                                        {
                                            WPT.SetSortColumn(Params[2]);
                                            WPT.SetSortOrder(Params[3]);
                                        }
                                        break;
                                    }
                                default:
                                    break;
                            }
                        }
                    }
                }
            }
            else
            {
                base.OnLoad(e);
            }

            //
            // Construct the user DataTable.  ConstructUserTable reads the 
            // users from ADAM.
            //
            ConstructUserTable();
        }

        //
        // ConstructUserTable
        // Arguments - none.
        // Description:
        //      Build the UserTable.  Key off of the user name.  Add columns for name and
        //      for management actions.  Query ADAM and populate the table.
        //
        protected void ConstructUserTable()
        {
            DataColumn[] key;
            DataColumn dc;

            key = new DataColumn[1];
            
            key[0] = new DataColumn(
                             ColumnNames[(int)INDEX.ID], 
                             typeof(String)
                             );

            WPT.GetTable().Columns.Add(key[0]);
            WPT.GetTable().PrimaryKey = key;

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.FIRSTNAME],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);
            
            dc = new DataColumn(
                         ColumnNames[(int)INDEX.LASTNAME],
                         typeof(String)
                         );

            WPT.GetTable().Columns.Add(dc);
            
            dc = new DataColumn(
                         ColumnNames[(int)INDEX.COMPANY],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);
            
            dc = new DataColumn(
                         ColumnNames[(int)INDEX.PHONE],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.REQUESTER],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.ENABLED],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.EXPIRE],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);

            dc = new DataColumn(
                         ColumnNames[(int)INDEX.ACTION],
                         typeof(String)
                         );
            WPT.GetTable().Columns.Add(dc);

            GetUserListFromADAM(WPT.GetTable());
        }

        //
        // Render
        // Arguments:
        //      writer - HtmlTextWriter that outputs the controls.
        // Description:
        //      Render draws the webpart.
        //
        protected override void Render(
                                    HtmlTextWriter writer
                                    )
        {
            string UserID;
            string FirstName;
            string LastName;
            string CompanyName;
            string PhoneNumber;
            string Requester;
            bool bEnabled;
            string Enabled;

            if (IsUserManager() == false)
            {
                writer.Write(Resources.NoPermissions);
                return;
            }

            writer.Write("<table border=\"0\" width=\"100%\" class=\"ms-authoringcontrols\">");
            writer.Write(@"<tr class=""grid-header"" align=""left"" style=""color:White;background-color:#5D7B9D;font-weight:bold;"">");

            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.ID], Resources.IDColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.FIRSTNAME], Resources.FirstNameColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.LASTNAME], Resources.LastNameColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.COMPANY], Resources.CompanyColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.PHONE], Resources.PhoneColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.REQUESTER], Resources.RequesterColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.ENABLED], Resources.EnabledColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.EXPIRE], Resources.ExpireColumnHeader) + "</th>");
            writer.Write(@"<th>" + WPT.SortLink(ColumnNames[(int)INDEX.ACTION], Resources.ActionColumnHeader) + "</th>");
            writer.Write("</tr>");

            foreach (DataRow dr in WPT.GetSortedRows(null))
            {
                string ActionLink = null;
                bool bModify = false;
                bool bExpired = false;
                                
                UserID = dr[(int)INDEX.ID].ToString().Trim();
                FirstName = dr[(int)INDEX.FIRSTNAME].ToString().Trim();
                LastName = dr[(int)INDEX.LASTNAME].ToString().Trim();
                CompanyName = dr[(int)INDEX.COMPANY].ToString().Trim();
                PhoneNumber = dr[(int)INDEX.PHONE].ToString().Trim();
                Requester = dr[(int)INDEX.REQUESTER].ToString().Trim();
                Enabled = dr[(int)INDEX.ENABLED].ToString().Trim();
                MembershipUser u = Membership.GetUser(UserID);
                bExpired = UM.PasswordExpired(u);

                if (Enabled == "Disabled")
                {
                    bEnabled = false;
                }
                else
                {
                    bEnabled = true;
                }

                if (UserID == SelectedUserID)
                {
                    switch (ActionLevel)
                    {
                        case "root":
                            {
                                //
                                // This indicates the top level, with choices to 
                                // Modify, Delete, Reset password, and toggle the enable
                                // state.
                                //

                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                                ActionLink += "action," + HttpUtility.HtmlEncode(UserID) + ",modify";
                                ActionLink += @"')"" style=""color:#333333;"">";
                                ActionLink += Resources.ModifyVerb;
                                ActionLink += "</a>";
                                ActionLink += " | ";
                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                                ActionLink += "resetpassword," + HttpUtility.HtmlEncode(UserID);
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.ResetPasswordVerb + "</a>";
                                ActionLink += " | ";

                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                                ActionLink += "deleteuser," + HttpUtility.HtmlEncode(UserID);
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.DeleteVerb + "</a>";
                                ActionLink += " | ";

                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                                ActionLink += "action," + HttpUtility.HtmlEncode(UserID) + ",enable";
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.ToggleVerb + "</a>";

                                ActionLink += " | ";
                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','";
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.CancelVerb + "</a>";

                                DebugLabel.Text += ActionLink;
                                break;
                            }
                        case "modify":
                            {
                                tbFirstName.Text = FirstName;
                                tbLastName.Text = LastName;
                                tbPhone.Text = PhoneNumber;
                                tbCompany.Text = CompanyName;

                                bModify = true;

                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                                ActionLink += "submitmods," + HttpUtility.HtmlEncode(UserID);
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.SubmitVerb + "</a> ";
                                ActionLink += " | ";

                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','";
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.CancelVerb + "</a>";
                                DebugLabel.Text += ActionLink;

                                break;
                            }
                        case "enable":
                            {
                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                                ActionLink += "enableuser," + HttpUtility.HtmlEncode(UserID);
                                ActionLink += @"')"" style=""color:#333333;"">";
                                if (bEnabled)
                                {
                                    ActionLink += Resources.DisableVerb + "</a>";
                                }
                                else
                                {
                                    ActionLink += Resources.EnableVerb + "</a>";
                                }

                                ActionLink += " | ";
                                ActionLink += @"<a href=""javascript:__doPostBack('__Page','";
                                ActionLink += @"')"" style=""color:#333333;"">" + Resources.CancelVerb + "</a>";
                                DebugLabel.Text += ActionLink;

                                break;
                            }
                        default:
                            break;
                    }
                    ActionLink = "";
                }
                else
                {
                    ActionLink = @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
                    ActionLink += "action," + HttpUtility.HtmlEncode(UserID) + ",root";
                    ActionLink += @"')"" style=""color:#333333;"">" + Resources.TakeActionVerb + "</a>";
                }

                

                // when we are acting on a certain user, only show that user so the admin
                // can figure out what they are doing
                if (SelectedUserID != null)
                {
                    if (UserID != SelectedUserID)
                    {
                        continue;
                    }
                }
                  

                writer.Write("<tr>");
                writer.Write("<td>" + HttpUtility.HtmlEncode(UserID) + "</td>");

                if (bModify)
                {
                    OutputTextbox(tbFirstName, writer);
                    OutputTextbox(tbLastName, writer);
                    OutputTextbox(tbCompany, writer);
                    OutputTextbox(tbPhone,  writer);
                }
                else
                {
                    writer.Write("<td>" + FirstName + "</td>");
                    writer.Write("<td>" + LastName + "</td>");
                    writer.Write("<td>" + CompanyName + "</td>");
                    writer.Write("<td>" + PhoneNumber + "</td>");
                }
                writer.Write("<td>" + Requester + "</td>");

                if (bEnabled)
                {
                    writer.Write("<td align=center>X</td>");
                }
                else
                {
                    writer.Write("<td> </td>");
                }

                if (bExpired)
                {
                    writer.Write("<td align=center>X</td>");
                }
                else
                {
                    writer.Write("<td></td>");
                }
                writer.Write("<td>" + ActionLink + "</td>");
                writer.Write("</tr>");
            }

            writer.Write("<tr><td colspan=7>");
            DebugLabel.RenderControl(writer);
            writer.Write("</td></tr>");

            writer.Write("</table>");
        }

        public void OutputTextbox(
                        TextBox tb,
                        HtmlTextWriter w
                        )
        {
            tb.MaxLength = 25;
            tb.Columns = 12;
            tb.CssClass = "ms-authoringcontrols";
            w.Write("<td>");
            tb.RenderControl(w);
            w.Write("</td>");
        }

        bool UpdateUser(string user, string givenName, string sn, string company, string telephoneNumber)
        {
            bool bSuccess = false;

            try
            {
                if (givenName == "")
                {
                    throw new Exception(Resources.FirstNameError);
                }
                if (sn == "")
                {
                    throw new Exception(Resources.LastNameError);
                }
                if (company == "")
                {
                    throw new Exception(Resources.CompanyError);
                }
                if (telephoneNumber == "")
                {
                    throw new Exception(Resources.PhoneError);
                }

                //
                // Set company, phone, and name information.
                //
                MembershipUser u = Membership.GetUser(user);
                UM.SetProfileInformation(u, company, givenName, sn, telephoneNumber);
                
                bSuccess = true;
            }
            catch (Exception Ex)
            {
               DebugLabel.Text += Ex.Message;
               DebugLabel.Text += " | ";
               DebugLabel.Text += @"<a href=""javascript:__doPostBack('__Page','" + WPT.GetTag() + ",";
               DebugLabel.Text += "action," + HttpUtility.HtmlEncode(user) + ",modify";
               DebugLabel.Text += @"')"" style=""color:#333333;"">";
               DebugLabel.Text += Resources.SubmitVerb;
               DebugLabel.Text += "</a>";
            }
            return bSuccess;
        } 
        
        //
        // GetUserListFromADAM
        // Arguments:
        //      dt - DataTable to which to add users.
        // Description:
        //      Populates dt with users from ADAM. 
        //
        public void GetUserListFromADAM(
                        DataTable dt
                        )
        {
            DataRow dr;
            SearchResultCollection src = null;
            bool bReverted = false;
            WindowsIdentity wi = null;

            try
            {
                wi = WindowsIdentity.GetCurrent();
                RevertToSelf();
                bReverted = true;
                WindowsIdentity.GetCurrent().Impersonate();
                // 
                // Get the search collection of entries from ADAM.
                //
                src = UM.FindAllUsers();

                for (int i = 0; i < src.Count; i++)
                {
                    SearchResult sr = src[i];
                    dr = dt.NewRow();
                    DirectoryEntry de = sr.GetDirectoryEntry();

                    //
                    // Move past the substring "CN="
                    //
                    dr[(int)INDEX.ID] = de.Name.Substring(3);

                    //
                    // Determine the enabled state of the user.
                    //
                    if (de.Properties["msDS-UserAccountDisabled"].Value.ToString().ToLower() == "false")
                    {
                        dr[(int)INDEX.ENABLED] = Resources.EnabledState;
                    }
                    else
                    {
                        dr[(int)INDEX.ENABLED] = Resources.DisabledState;
                    }

                    //
                    // Pick up the other attributes.
                    //
                    if (de.Properties["givenName"].Value != null)
                    {
                        dr[(int)INDEX.FIRSTNAME] = de.Properties["givenName"].Value.ToString();
                    }
                    if (de.Properties["sn"].Value != null)
                    {
                        dr[(int)INDEX.LASTNAME] = de.Properties["sn"].Value.ToString();
                    }
                    if (de.Properties["company"].Value != null)
                    {
                        dr[(int)INDEX.COMPANY] = de.Properties["company"].Value.ToString();
                    }
                    if (de.Properties["telephoneNumber"].Value != null)
                    {
                        dr[(int)INDEX.PHONE] = de.Properties["telephoneNumber"].Value.ToString();
                    }
                    if (de.Properties["eatmuRequester"].Value != null)
                    {
                        dr[(int)INDEX.REQUESTER] = de.Properties["eatmuRequester"].Value.ToString();
                    }

                    dt.Rows.Add(dr);
                }
            }
            catch (Exception e)
            {
                DebugLabel.Text += e.Message;
            }
            finally
            {
                if (bReverted && wi != null)
                {
                    wi.Impersonate();
                }
            }
        }

        //
        // ResetUserPassword
        // Arguments:
        //      Username - user who will get a new password.
        // Description:
        //      Generates a new password with Membership.GeneratePassword and 
        //      uses Invoke() to set the password on the user in ADAM.
        //
        public string ResetUserPassword(
                          string Username
                          )
        {
            string Password = null;
            try
            {
                Password = UM.ResetPassword(Username);
            }
            catch (Exception e)
            {
                DebugLabel.Text += e.Message;
            }
            return Password;
        }

        //
        // DeleteUser
        // Arguments:
        //      Username - user to delete.
        // Description:
        //      Gets the user DirectoryEntry and calls DeleteTree on that object.
        //
        public bool DeleteUser(
                        string Username
                        )
        {
            UM.DeleteUser(Username);
            return true;
        }

        //
        // IsUserManager
        // Description:
        //      Determines if the current user is in the UserManagementGroup.
        //
        bool IsUserManager()
        {
            return WPT.IsUserInConfigGroup(
                       SPControl.GetContextWeb(Context).CurrentUser,
                       "UserManagementGroup"
                       );
        }
    }
}